/**
 * 粒子效果系统
 * 处理游戏中的各种粒子特效，如爆炸、收集、轨迹等
 */

/**
 * 粒子类型枚举
 */
export enum ParticleType {
  /** 爆炸粒子 */
  EXPLOSION = 'explosion',
  /** 收集粒子 */
  COLLECT = 'collect',
  /** 轨迹粒子 */
  TRAIL = 'trail',
  /** 火花粒子 */
  SPARK = 'spark',
  /** 烟雾粒子 */
  SMOKE = 'smoke',
  /** 星星粒子 */
  STAR = 'star',
  /** 光芒粒子 */
  GLOW = 'glow',
  /** 碎片粒子 */
  DEBRIS = 'debris'
}

/**
 * 粒子混合模式枚举
 */
export enum BlendMode {
  NORMAL = 'source-over',
  ADD = 'lighter',
  MULTIPLY = 'multiply',
  SCREEN = 'screen'
}

/**
 * 向量2D接口
 */
export interface Vector2D {
  x: number
  y: number
}

/**
 * 颜色接口
 */
export interface Color {
  r: number
  g: number
  b: number
  a: number
}

/**
 * 粒子配置接口
 */
export interface ParticleConfig {
  /** 粒子类型 */
  type: ParticleType
  /** 初始位置 */
  position: Vector2D
  /** 初始速度 */
  velocity: Vector2D
  /** 加速度 */
  acceleration?: Vector2D
  /** 初始大小 */
  size: number
  /** 大小变化率 */
  sizeDecay?: number
  /** 初始颜色 */
  color: Color
  /** 颜色变化 */
  colorDecay?: Partial<Color>
  /** 生命周期（毫秒） */
  lifetime: number
  /** 重力影响 */
  gravity?: number
  /** 阻力系数 */
  friction?: number
  /** 旋转角度 */
  rotation?: number
  /** 旋转速度 */
  rotationSpeed?: number
  /** 混合模式 */
  blendMode?: BlendMode
  /** 纹理路径 */
  texture?: string
  /** 是否发光 */
  glow?: boolean
  /** 发光强度 */
  glowIntensity?: number
}

/**
 * 粒子类
 */
export class Particle {
  public position: Vector2D
  public velocity: Vector2D
  public acceleration: Vector2D
  public size: number
  public sizeDecay: number
  public color: Color
  public colorDecay: Partial<Color>
  public lifetime: number
  public maxLifetime: number
  public gravity: number
  public friction: number
  public rotation: number
  public rotationSpeed: number
  public blendMode: BlendMode
  public texture?: string
  public glow: boolean
  public glowIntensity: number
  public type: ParticleType
  public isDead: boolean = false

  /**
   * 创建粒子实例
   * @param config - 粒子配置
   */
  constructor(config: ParticleConfig) {
    this.type = config.type
    this.position = { ...config.position }
    this.velocity = { ...config.velocity }
    this.acceleration = config.acceleration || { x: 0, y: 0 }
    this.size = config.size
    this.sizeDecay = config.sizeDecay || 0
    this.color = { ...config.color }
    this.colorDecay = config.colorDecay || {}
    this.lifetime = config.lifetime
    this.maxLifetime = config.lifetime
    this.gravity = config.gravity || 0
    this.friction = config.friction || 1
    this.rotation = config.rotation || 0
    this.rotationSpeed = config.rotationSpeed || 0
    this.blendMode = config.blendMode || BlendMode.NORMAL
    this.texture = config.texture
    this.glow = config.glow || false
    this.glowIntensity = config.glowIntensity || 1
  }

  /**
   * 更新粒子状态
   * @param deltaTime - 时间增量（毫秒）
   */
  public update(deltaTime: number): void {
    if (this.isDead) return

    // 更新生命周期
    this.lifetime -= deltaTime
    if (this.lifetime <= 0) {
      this.isDead = true
      return
    }

    // 计算生命周期比例
    const lifeRatio = this.lifetime / this.maxLifetime

    // 更新位置
    this.velocity.x += this.acceleration.x * deltaTime / 1000
    this.velocity.y += this.acceleration.y * deltaTime / 1000

    // 应用重力
    if (this.gravity !== 0) {
      this.velocity.y += this.gravity * deltaTime / 1000
    }

    // 应用阻力
    if (this.friction !== 1) {
      const frictionFactor = Math.pow(this.friction, deltaTime / 1000)
      this.velocity.x *= frictionFactor
      this.velocity.y *= frictionFactor
    }

    // 更新位置
    this.position.x += this.velocity.x * deltaTime / 1000
    this.position.y += this.velocity.y * deltaTime / 1000

    // 更新旋转
    this.rotation += this.rotationSpeed * deltaTime / 1000

    // 更新大小
    if (this.sizeDecay !== 0) {
      this.size = Math.max(0, this.size - this.sizeDecay * deltaTime / 1000)
    }

    // 更新颜色
    if (this.colorDecay.r !== undefined) {
      this.color.r = Math.max(0, this.color.r - this.colorDecay.r * deltaTime / 1000)
    }
    if (this.colorDecay.g !== undefined) {
      this.color.g = Math.max(0, this.color.g - this.colorDecay.g * deltaTime / 1000)
    }
    if (this.colorDecay.b !== undefined) {
      this.color.b = Math.max(0, this.color.b - this.colorDecay.b * deltaTime / 1000)
    }
    if (this.colorDecay.a !== undefined) {
      this.color.a = Math.max(0, this.color.a - this.colorDecay.a * deltaTime / 1000)
    }
  }

  /**
   * 渲染粒子
   * @param ctx - Canvas渲染上下文
   */
  public render(ctx: CanvasRenderingContext2D): void {
    if (this.isDead || this.size <= 0 || this.color.a <= 0) return

    ctx.save()

    // 设置混合模式
    ctx.globalCompositeOperation = this.blendMode

    // 移动到粒子位置
    ctx.translate(this.position.x, this.position.y)

    // 应用旋转
    if (this.rotation !== 0) {
      ctx.rotate(this.rotation)
    }

    // 设置颜色和透明度
    const { r, g, b, a } = this.color
    ctx.fillStyle = `rgba(${Math.floor(r)}, ${Math.floor(g)}, ${Math.floor(b)}, ${a})`

    // 应用发光效果
    if (this.glow && this.glowIntensity > 0) {
      ctx.shadowColor = ctx.fillStyle
      ctx.shadowBlur = this.size * this.glowIntensity
    }

    // 渲染粒子
    if (this.texture) {
      // 如果有纹理，渲染纹理（这里简化为圆形）
      this.renderCircle(ctx)
    } else {
      // 根据粒子类型渲染不同形状
      this.renderByType(ctx)
    }

    ctx.restore()
  }

  /**
   * 渲染圆形粒子
   * @param ctx - Canvas渲染上下文
   */
  private renderCircle(ctx: CanvasRenderingContext2D): void {
    ctx.beginPath()
    ctx.arc(0, 0, this.size, 0, Math.PI * 2)
    ctx.fill()
  }

  /**
   * 根据类型渲染粒子
   * @param ctx - Canvas渲染上下文
   */
  private renderByType(ctx: CanvasRenderingContext2D): void {
    switch (this.type) {
      case ParticleType.EXPLOSION:
      case ParticleType.COLLECT:
      case ParticleType.GLOW:
        this.renderCircle(ctx)
        break

      case ParticleType.STAR:
        this.renderStar(ctx)
        break

      case ParticleType.SPARK:
        this.renderSpark(ctx)
        break

      case ParticleType.DEBRIS:
        this.renderDebris(ctx)
        break

      case ParticleType.TRAIL:
        this.renderTrail(ctx)
        break

      default:
        this.renderCircle(ctx)
        break
    }
  }

  /**
   * 渲染星形粒子
   * @param ctx - Canvas渲染上下文
   */
  private renderStar(ctx: CanvasRenderingContext2D): void {
    const spikes = 5
    const outerRadius = this.size
    const innerRadius = this.size * 0.5

    ctx.beginPath()
    for (let i = 0; i < spikes * 2; i++) {
      const angle = (i * Math.PI) / spikes
      const radius = i % 2 === 0 ? outerRadius : innerRadius
      const x = Math.cos(angle) * radius
      const y = Math.sin(angle) * radius

      if (i === 0) {
        ctx.moveTo(x, y)
      } else {
        ctx.lineTo(x, y)
      }
    }
    ctx.closePath()
    ctx.fill()
  }

  /**
   * 渲染火花粒子
   * @param ctx - Canvas渲染上下文
   */
  private renderSpark(ctx: CanvasRenderingContext2D): void {
    const length = this.size * 2
    ctx.beginPath()
    ctx.moveTo(-length / 2, 0)
    ctx.lineTo(length / 2, 0)
    ctx.lineWidth = Math.max(1, this.size / 4)
    ctx.strokeStyle = ctx.fillStyle
    ctx.stroke()
  }

  /**
   * 渲染碎片粒子
   * @param ctx - Canvas渲染上下文
   */
  private renderDebris(ctx: CanvasRenderingContext2D): void {
    const size = this.size
    ctx.fillRect(-size / 2, -size / 2, size, size)
  }

  /**
   * 渲染轨迹粒子
   * @param ctx - Canvas渲染上下文
   */
  private renderTrail(ctx: CanvasRenderingContext2D): void {
    const length = this.size * 3
    const width = this.size
    
    ctx.beginPath()
    ctx.ellipse(0, 0, length / 2, width / 2, 0, 0, Math.PI * 2)
    ctx.fill()
  }
}

/**
 * 粒子发射器配置接口
 */
export interface EmitterConfig {
  /** 发射器位置 */
  position: Vector2D
  /** 发射速率（粒子/秒） */
  emissionRate: number
  /** 粒子配置模板 */
  particleTemplate: Partial<ParticleConfig>
  /** 发射角度范围（弧度） */
  angleRange?: { min: number; max: number }
  /** 速度范围 */
  velocityRange?: { min: number; max: number }
  /** 大小范围 */
  sizeRange?: { min: number; max: number }
  /** 生命周期范围 */
  lifetimeRange?: { min: number; max: number }
  /** 发射器持续时间（毫秒，-1为无限） */
  duration?: number
  /** 是否自动开始 */
  autoStart?: boolean
}

/**
 * 粒子发射器类
 */
export class ParticleEmitter {
  public position: Vector2D
  public emissionRate: number
  public particleTemplate: Partial<ParticleConfig>
  public angleRange: { min: number; max: number }
  public velocityRange: { min: number; max: number }
  public sizeRange: { min: number; max: number }
  public lifetimeRange: { min: number; max: number }
  public duration: number
  public isActive: boolean = false
  public particles: Particle[] = []

  private emissionTimer: number = 0
  private durationTimer: number = 0

  /**
   * 创建粒子发射器实例
   * @param config - 发射器配置
   */
  constructor(config: EmitterConfig) {
    this.position = { ...config.position }
    this.emissionRate = config.emissionRate
    this.particleTemplate = { ...config.particleTemplate }
    this.angleRange = config.angleRange || { min: 0, max: Math.PI * 2 }
    this.velocityRange = config.velocityRange || { min: 50, max: 100 }
    this.sizeRange = config.sizeRange || { min: 2, max: 8 }
    this.lifetimeRange = config.lifetimeRange || { min: 500, max: 2000 }
    this.duration = config.duration || -1
    
    if (config.autoStart) {
      this.start()
    }
  }

  /**
   * 开始发射粒子
   */
  public start(): void {
    this.isActive = true
    this.durationTimer = this.duration
  }

  /**
   * 停止发射粒子
   */
  public stop(): void {
    this.isActive = false
  }

  /**
   * 更新发射器状态
   * @param deltaTime - 时间增量（毫秒）
   */
  public update(deltaTime: number): void {
    // 更新持续时间
    if (this.isActive && this.duration > 0) {
      this.durationTimer -= deltaTime
      if (this.durationTimer <= 0) {
        this.stop()
      }
    }

    // 发射新粒子
    if (this.isActive) {
      this.emissionTimer += deltaTime
      const emissionInterval = 1000 / this.emissionRate
      
      while (this.emissionTimer >= emissionInterval) {
        this.emitParticle()
        this.emissionTimer -= emissionInterval
      }
    }

    // 更新现有粒子
    for (let i = this.particles.length - 1; i >= 0; i--) {
      const particle = this.particles[i]
      particle.update(deltaTime)
      
      // 移除死亡的粒子
      if (particle.isDead) {
        this.particles.splice(i, 1)
      }
    }
  }

  /**
   * 发射单个粒子
   */
  private emitParticle(): void {
    // 生成随机属性
    const angle = this.randomBetween(this.angleRange.min, this.angleRange.max)
    const velocity = this.randomBetween(this.velocityRange.min, this.velocityRange.max)
    const size = this.randomBetween(this.sizeRange.min, this.sizeRange.max)
    const lifetime = this.randomBetween(this.lifetimeRange.min, this.lifetimeRange.max)

    // 创建粒子配置
    const particleConfig: ParticleConfig = {
      type: ParticleType.EXPLOSION,
      position: { ...this.position },
      velocity: {
        x: Math.cos(angle) * velocity,
        y: Math.sin(angle) * velocity
      },
      size,
      lifetime,
      color: { r: 255, g: 255, b: 255, a: 1 },
      ...this.particleTemplate
    }

    // 创建并添加粒子
    const particle = new Particle(particleConfig)
    this.particles.push(particle)
  }

  /**
   * 生成指定范围内的随机数
   * @param min - 最小值
   * @param max - 最大值
   * @returns 随机数
   */
  private randomBetween(min: number, max: number): number {
    return min + Math.random() * (max - min)
  }

  /**
   * 渲染发射器的所有粒子
   * @param ctx - Canvas渲染上下文
   */
  public render(ctx: CanvasRenderingContext2D): void {
    this.particles.forEach(particle => {
      particle.render(ctx)
    })
  }

  /**
   * 获取活动粒子数量
   * @returns 活动粒子数量
   */
  public getParticleCount(): number {
    return this.particles.length
  }

  /**
   * 清除所有粒子
   */
  public clear(): void {
    this.particles = []
  }
}

/**
 * 粒子系统类
 * 管理多个粒子发射器和全局粒子效果
 */
export class ParticleSystem {
  private emitters: Map<string, ParticleEmitter> = new Map()
  private canvas: HTMLCanvasElement
  private ctx: CanvasRenderingContext2D
  private isRunning: boolean = false
  private lastUpdateTime: number = 0

  /**
   * 创建粒子系统实例
   * @param canvas - Canvas元素
   */
  constructor(canvas: HTMLCanvasElement) {
    this.canvas = canvas
    const ctx = canvas.getContext('2d')
    if (!ctx) {
      throw new Error('无法获取Canvas 2D渲染上下文')
    }
    this.ctx = ctx
  }

  /**
   * 启动粒子系统
   */
  public start(): void {
    if (this.isRunning) return
    
    this.isRunning = true
    this.lastUpdateTime = performance.now()
    this.update()
  }

  /**
   * 停止粒子系统
   */
  public stop(): void {
    this.isRunning = false
  }

  /**
   * 更新粒子系统
   */
  private update(): void {
    if (!this.isRunning) return

    const currentTime = performance.now()
    const deltaTime = currentTime - this.lastUpdateTime
    this.lastUpdateTime = currentTime

    // 更新所有发射器
    this.emitters.forEach(emitter => {
      emitter.update(deltaTime)
    })

    // 渲染
    this.render()

    // 继续更新循环
    requestAnimationFrame(() => this.update())
  }

  /**
   * 渲染所有粒子
   */
  private render(): void {
    // 清除画布
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)

    // 渲染所有发射器的粒子
    this.emitters.forEach(emitter => {
      emitter.render(this.ctx)
    })
  }

  /**
   * 添加粒子发射器
   * @param id - 发射器ID
   * @param config - 发射器配置
   * @returns 粒子发射器实例
   */
  public addEmitter(id: string, config: EmitterConfig): ParticleEmitter {
    const emitter = new ParticleEmitter(config)
    this.emitters.set(id, emitter)
    return emitter
  }

  /**
   * 获取粒子发射器
   * @param id - 发射器ID
   * @returns 粒子发射器实例或undefined
   */
  public getEmitter(id: string): ParticleEmitter | undefined {
    return this.emitters.get(id)
  }

  /**
   * 移除粒子发射器
   * @param id - 发射器ID
   * @returns 是否成功移除
   */
  public removeEmitter(id: string): boolean {
    const emitter = this.emitters.get(id)
    if (emitter) {
      emitter.stop()
      emitter.clear()
      return this.emitters.delete(id)
    }
    return false
  }

  /**
   * 创建爆炸效果
   * @param position - 爆炸位置
   * @param intensity - 爆炸强度（1-10）
   * @returns 发射器ID
   */
  public createExplosion(position: Vector2D, intensity: number = 5): string {
    const id = `explosion_${Date.now()}_${Math.random()}`
    
    const config: EmitterConfig = {
      position,
      emissionRate: intensity * 50,
      duration: 200,
      autoStart: true,
      particleTemplate: {
        type: ParticleType.EXPLOSION,
        color: { r: 255, g: 100, b: 0, a: 1 },
        colorDecay: { a: 2 },
        gravity: 200,
        friction: 0.95,
        blendMode: BlendMode.ADD,
        glow: true,
        glowIntensity: 2
      },
      velocityRange: { min: 50 * intensity, max: 150 * intensity },
      sizeRange: { min: 2, max: 8 * intensity },
      lifetimeRange: { min: 300, max: 800 }
    }

    this.addEmitter(id, config)
    return id
  }

  /**
   * 创建收集效果
   * @param position - 收集位置
   * @param targetPosition - 目标位置
   * @returns 发射器ID
   */
  public createCollectEffect(position: Vector2D, targetPosition: Vector2D): string {
    const id = `collect_${Date.now()}_${Math.random()}`
    
    const config: EmitterConfig = {
      position,
      emissionRate: 30,
      duration: 300,
      autoStart: true,
      particleTemplate: {
        type: ParticleType.COLLECT,
        color: { r: 255, g: 215, b: 0, a: 1 },
        colorDecay: { a: 1 },
        blendMode: BlendMode.ADD,
        glow: true,
        glowIntensity: 1.5
      },
      velocityRange: { min: 20, max: 60 },
      sizeRange: { min: 3, max: 6 },
      lifetimeRange: { min: 500, max: 1000 }
    }

    this.addEmitter(id, config)
    return id
  }

  /**
   * 创建轨迹效果
   * @param position - 起始位置
   * @returns 发射器ID
   */
  public createTrailEffect(position: Vector2D): string {
    const id = `trail_${Date.now()}_${Math.random()}`
    
    const config: EmitterConfig = {
      position,
      emissionRate: 20,
      duration: -1, // 持续发射
      autoStart: true,
      particleTemplate: {
        type: ParticleType.TRAIL,
        color: { r: 100, g: 150, b: 255, a: 0.8 },
        colorDecay: { a: 1.5 },
        friction: 0.98,
        blendMode: BlendMode.ADD
      },
      angleRange: { min: Math.PI, max: Math.PI * 2 },
      velocityRange: { min: 10, max: 30 },
      sizeRange: { min: 1, max: 3 },
      lifetimeRange: { min: 200, max: 500 }
    }

    this.addEmitter(id, config)
    return id
  }

  /**
   * 获取总粒子数量
   * @returns 总粒子数量
   */
  public getTotalParticleCount(): number {
    let total = 0
    this.emitters.forEach(emitter => {
      total += emitter.getParticleCount()
    })
    return total
  }

  /**
   * 清除所有粒子效果
   */
  public clear(): void {
    this.emitters.forEach(emitter => {
      emitter.stop()
      emitter.clear()
    })
    this.emitters.clear()
  }

  /**
   * 获取发射器数量
   * @returns 发射器数量
   */
  public getEmitterCount(): number {
    return this.emitters.size
  }

  /**
   * 设置Canvas大小
   * @param width - 宽度
   * @param height - 高度
   */
  public setCanvasSize(width: number, height: number): void {
    this.canvas.width = width
    this.canvas.height = height
  }

  /**
   * 销毁粒子系统
   */
  public dispose(): void {
    this.stop()
    this.clear()
  }
}